package com.settlement.system.common.util;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.settlement.system.common.constant.SecurityConstants;
import com.settlement.system.common.result.Result;
import com.settlement.system.model.entity.SysLazyToolUser;
import com.settlement.system.service.SysLazyToolUserService;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;

/**
 * 请求工具类
 *
 * @author haoxr
 */
public class RequestUtils {

    private static final Logger logger = LoggerFactory.getLogger(RequestUtils.class);

    /**
     * 请求头解析获取 Token
     */
    public static String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader(SecurityConstants.TOKEN_KEY);
        if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            return bearerToken.substring(SecurityConstants.TOKEN_PREFIX.length());
        }
        return null;
    }

    /**
     * 移动端检查Token是否合法
     */
    public static Result<?> resolveMobileToken(HttpServletRequest request, String secret, SysLazyToolUserService sysLazyToolUserService) {
        String appId = request.getParameter("appId");
        // 根据appId查询用户
        if (StringUtils.isMobile(appId)) {
            // 十一位长度是手机号码，不用进入此判断
            SysLazyToolUser sysLazyToolUser =
                    sysLazyToolUserService.getOne(new LambdaQueryWrapper<SysLazyToolUser>().eq(SysLazyToolUser::getMobile, appId));
            if (sysLazyToolUser == null) {
                return Result.failed("用户【%s】不存在".formatted(appId));
            }
        }
        String sign = request.getParameter("sign");
        if (StringUtils.isEmpty(sign)) {
            return Result.failed("签名参数为空");
        }
        String timestamp = request.getParameter("timestamp");
        // 时间戳要为13位的毫秒级时间戳
        if (timestamp.length() != 13) {
            return Result.failed("时间长度错误");
        }
        //check时间戳的值是否在当前时间戳前后一30秒以内
        String currTimestamp = String.valueOf(System.currentTimeMillis());
        long currTimestampNum = Long.parseLong(currTimestamp);
        long verifyTimestampNum;
        try {
            verifyTimestampNum = Long.parseLong(timestamp);
        } catch (NumberFormatException e) {
            return Result.failed("时间签名错误");
        }
        // 在30秒范围之外，访问已过期
        if (Math.abs(verifyTimestampNum - currTimestampNum) > 1000 * 30) {
            return Result.failed("访问已过期");
        }
        if (sign.equals(getSign(appId + timestamp, secret))) {
            return Result.success();
        }
        return Result.failed("签名失败");
    }

    /**
     * 得到签名
     *
     * @param content 参数集合,不含密钥secret
     * @param secret  分配的密钥secret
     * @return sign 签名
     */
    private static String getSign(String content, String secret) {
        byte[] md5Digest;
        // Md5加密得到sign
        md5Digest = getMd5Digest(content + secret);
        return byte2hex(md5Digest);
    }

    /**
     * 获取md5信息摘要
     *
     * @param data 需要加密的字符串
     * @return bytes 字节数组
     */
    private static byte[] getMd5Digest(String data) {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data.getBytes(StandardCharsets.UTF_8));
        } catch (GeneralSecurityException gse) {
            logger.error("生成签名错误", gse);
        }
        return bytes;
    }

    /**
     * 将字节数组转化为16进制
     *
     * @param bytes 字节数组
     * @return sign 签名
     */
    private static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (byte aByte : bytes) {
            String hex = Integer.toHexString(aByte & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }

    public static void main(String[] args) throws Exception {
        String timestamp = String.valueOf(System.currentTimeMillis());
        System.out.println(timestamp);
//        /*String text = "1703753641064";
//        Instant instant = Instant.ofEpochMilli(Long.parseLong(text));
//        System.out.println(LocalDateTime.ofInstant(instant, ZoneId.systemDefault()));*/
        String appId = "1";
        String secret = "P4I8HCOP1OP7432XZVKR2MPJKKVQ7J";
        System.out.println(getSign(appId + timestamp, secret));
    }
}
